using System;
using NLog;
using WCell.Constants;
using WCell.Core;
using WCell.Core.Network;
using WCell.Util.Threading;
using WCell.RealmServer.Network;
using WCell.Util;

namespace WCell.RealmServer.Handlers
{
	public static class LoginHandler
	{
		private static Logger log = LogManager.GetCurrentClassLogger();

		/// <summary>
		/// Handles an incoming auth session request.
		/// </summary>
		/// <param name="client">the Session the incoming packet belongs to</param>
		/// <param name="packet">the full packet</param>
		[ClientPacketHandler(RealmServerOpCode.CMSG_AUTH_SESSION, IsGamePacket = false, RequiresLogin = false)]
		public static void AuthSessionRequest(IRealmClient client, RealmPacketIn packet)
		{
			if (client.ActiveCharacter != null || client.Account != null)
			{
				// Already logged in
				SendAuthSessionErrorReply(client, LoginErrorCode.AUTH_ALREADY_ONLINE);
				client.Disconnect();
			}
			else if (!client.IsEncrypted)
			{
				var builtNumberClient = packet.ReadUInt32();

                uint new302 = packet.ReadUInt32(); // NEW 0.0.2.8970
				
				var accName = packet.ReadCString();

				var unk322 = packet.ReadUInt32();
				

				client.ClientSeed = packet.ReadUInt32();
			

				var unk4 = packet.ReadUInt64();

				client.ClientDigest = packet.ReadBigInteger(20);

#if DEBUG
				log.Debug("builtNumberClient:{0} new302:{1} accName:{2} unk322:{3} client.ClientSeed:{4} unk4:{5} ClientDigest:{6}",
					builtNumberClient,
					new302, accName, unk322, client.ClientSeed, unk4, client.ClientDigest);
#endif

			    int decompressedDataLength = packet.ReadInt32();
			    var compressedData = packet.ReadBytes(packet.RemainingLength);
                client.Addons = new byte[decompressedDataLength];
			    Compression.DecompressZLib(compressedData, client.Addons);

				var acctLoadTask = new Message2<IRealmClient, string>(client, accName, RealmAccount.InitializeAccount);
				client.Server.AddMessage(acctLoadTask);
			}
		}

        /// <summary>
        /// Send packet generated by the server to initialize authentification
        /// </summary>
        /// <param name="client">the client to send to</param>
        public static void SendAuthChallenge(IRealmClient client)
        {
            using (var packet = new RealmPacketOut(RealmServerOpCode.SMSG_AUTH_CHALLENGE))
            {
                packet.Write(1); // 1...31
                packet.Write(RealmServer.Instance.AuthSeed);

                // new 3.2.2 random data
				packet.WriteUInt(0xF3539DA3);
				packet.WriteUInt(0x6E8547B9);
				packet.WriteUInt(0x9A6AA2F8);
				packet.WriteUInt(0xA4F170F4);

                client.Send(packet);
            }
        }

		/// <summary>
		/// Sends an auth session error response to the client.
		/// </summary>
		/// <param name="client">the client to send to</param>
		/// <param name="error">the error code</param>
		public static void SendAuthSessionErrorReply(IPacketReceiver client, LoginErrorCode error)
		{
			using (var packet = new RealmPacketOut(RealmServerOpCode.SMSG_AUTH_RESPONSE, 1))
			{
				packet.WriteByte((byte)error);

				client.Send(packet);
			}
		}

		/// <summary>
		/// Sends an auth session success response to the client.
		/// </summary>
		/// <param name="client">the client to send to</param>
		public static void SendAuthSessionSuccess(IRealmClient client)
		{
			using (var packet = new RealmPacketOut(RealmServerOpCode.SMSG_AUTH_RESPONSE, 11))
			{
                packet.WriteByte((byte)LoginErrorCode.AUTH_OK);

                //BillingTimeRemaining
                packet.Write(0);

				packet.Write((byte)0x02);// BillingPlan Flags
                // 0x2, 0x4, 0x10 mutually exclusive. Order of Precedence: 0x2 > 0x4 > 0x10
                // 0x2 -> No Time left?
                // 0x20
                // 0x8

                // BillingTimeRested
				packet.Write(0);
				packet.Write((byte)client.Account.ClientId);

				client.Send(packet);
			}

		    ClientAddonHandler.SendAddOnInfoPacket(client);

			RealmServer.Instance.OnClientAccepted(null, null);
		}

		/// <summary>
		/// Sends the number of currently queued clients.
		/// </summary>
		/// <param name="client">the client to send to</param>
		public static void SendAuthQueueStatus(IRealmClient client)
		{
			using (var packet = new RealmPacketOut(RealmServerOpCode.SMSG_AUTH_RESPONSE))
			{
				packet.WriteByte((byte)LoginErrorCode.AUTH_WAIT_QUEUE);
				packet.Write(AuthQueue.QueuedClients + 1);

				client.Send(packet);
			}
		}
	}
}
